// Copyright (C) 2002-2005 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h

#ifndef __C_AXIAL_PARTICLE_SYSTEM_SCENE_NODE_H_INCLUDED__
#define __C_AXIAL_PARTICLE_SYSTEM_SCENE_NODE_H_INCLUDED__

#include "ISceneNode.h"
#include "irrArray.h"
#include "irrList.h"
#include "S3DVertex.h"

namespace irr
{
namespace scene
{

class CAxialParticle
{
public:
  CAxialParticle() : pos(0,0,0), rot(0,0,0), velocity(0,0,0), spin(0,0,0), 
					 size(5), endTime(0), color(255,255,255,255) {}
  
  core::vector3df		pos;		 // position
  core::vector3df		rot;		 // rotation
  core::vector3df		velocity;	// direction/ms
  core::vector3df		spin;		// rotation/ms
  f32					size;		// size of particle
  video::SColor		  color;	   // spelt da americans ways
  s16					sprite;	  // current sprite number
  s16					startFrame;  // animation: start of the loop
  s16					endFrame;	// animation: end of the loop
  s16					fps;		 // animation: frames per second
  u8					 animFlags;   // animation: 1=playing, 2=repeat, 4=backwards, 8=pingpong

  u32					endTime;	 // the time that this dies

  u32					user;		// user variable, pointer, whatever you like  

  void setPlaying  (bool playing)   { if (playing)   animFlags|=1; else animFlags&=(1^animFlags); }
  void setRepeat   (bool repeat)	{ if (repeat)	animFlags|=2; else animFlags&=(2^animFlags); }
  void setBackwards(bool backwards) { if (backwards) animFlags|=4; else animFlags&=(4^animFlags); }
  void setPingPong (bool pingpong)  { if (pingpong)  animFlags|=8; else animFlags&=(8^animFlags); }

};

//! A particle system scene node.
/** A scene node controlling a particle System. The behavior of the particles
can be controlling by setting the right particle emitters and effectors.
*/
class CAxialParticleSystemSceneNode: public ISceneNode
{
public:

	//! constructor
	CAxialParticleSystemSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, 
								  core::dimension2d<s32>imagecount = core::dimension2d<s32>(1,1),
								  s32 mirrory = 0 );

	//! destructor
	virtual ~CAxialParticleSystemSceneNode();

	//! Returns the material based on the zero based index i.
	virtual video::SMaterial& getMaterial(u32 i);

	//! Returns amount of materials used by this scene node.
	virtual u32 getMaterialCount();

	//! register node for rendering
	virtual void OnRegisterSceneNode();

	//! Animate node
	virtual void OnAnimate(u32 time);

	//! render
	virtual void render();

	//! returns the axis aligned bounding box of this node
	virtual const core::aabbox3d<f32>& getBoundingBox() const;

	//! Sets the size of all particles.
	virtual void setParticleSize(
		const core::dimension2d<f32> &size = core::dimension2d<f32>(10.0f, 10.0f));
		
	void addParticles(s32 count=1);
	
	CAxialParticle* getParticles()	 { return &Particles[0]; }
	s32			 getParticleCount() { return Particles.size(); }
	void			setAxis(s32 Xis0_Yis1_Zis2){ Axis = Xis0_Yis1_Zis2; }

private:

	void doParticleSystem(u32 time);
	void reallocateBuffers();
	s32  Axis;

	core::array<CAxialParticle> Particles;
	video::SMaterial Material;
	core::aabbox3d<f32> Box;
	u32 lastEmitTime;
	core::dimension2d<f32> ParticleSize;

	core::array<video::S3DVertex> Vertices; // 4 vertices per particle
	core::array<u16> Indices; // 6 indices per particle

	core::dimension2d<s32> ImageCount;	  // number of sprites
	s32					MirrorY;		 // less images for symmetrical shapes

	core::vector3df getTargetAngle(core::vector3df v, core::vector3df r)
	{
	   //v -position
	   //r -target
   
	   core::vector3df angle;
	   float x,y,z;
	   x = r.X - v.X;
	   y = r.Y - v.Y;
	   z = r.Z - v.Z;
	   
	   //angle in X-Z plane
	   angle.Y = atan2 (x, z);
	   angle.Y *= (180 / 3.14159265); //converting from rad to degrees
	   //angle.Y-=90;
	   //just making sure angle is somewhere between 0-360 degrees
	   if(angle.Y < 0) angle.Y += 360;
	   if(angle.Y >= 360) angle.Y -= 360;
	   
	   //angle in Y-Z plane while Z and X axes are already rotated around Y
	   float z1 = sqrt(x*x + z*z);
	   
	   angle.X = atan2 (z1, y);
	   angle.X *= (180 / 3.14159265); //converting from rad to degrees
	   //angle.X -= 90;
	   
	   //just making sure angle is somewhere between 0-360 degrees
	   if(angle.X < 0) angle.X += 360;
	   if(angle.X >= 360) angle.X -= 360;
   
	   return angle;
	} 


};

} // end namespace scene
} // end namespace irr


#endif

